<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="Pjdy8" id="Pjdy8"><span data-lake-id="u41ac49d5" id="u41ac49d5">典型回答</span></h1>
  <p data-lake-id="u6925ec46" id="u6925ec46"><br></p>
  <p data-lake-id="u309f1eef" id="u309f1eef"><span data-lake-id="u722ad5a7" id="u722ad5a7">Spring的事务传播机制用于控制在多个事务方法相互调用时事务的行为。</span></p>
  <p data-lake-id="ub35cce93" id="ub35cce93"><span data-lake-id="u51e88b62" id="u51e88b62">​</span><br></p>
  <p data-lake-id="uc80888c3" id="uc80888c3"><span data-lake-id="u7f321624" id="u7f321624">在复杂的业务场景中，多个事务方法之间的调用可能会导致事务的不一致，如出现数据丢失、重复提交等问题，使用事务传播机制可以避免这些问题的发生，保证事务的一致性和完整性。</span></p>
  <p data-lake-id="u3d429488" id="u3d429488"><span data-lake-id="u2aacacc9" id="u2aacacc9">​</span><br></p>
  <p data-lake-id="u222f69dc" id="u222f69dc"><span data-lake-id="u6d40ad9b" id="u6d40ad9b">Spring的事务规定了7种事务的传播级别，默认的传播机制是</span><strong><span data-lake-id="u644b2bc5" id="u644b2bc5" style="color: rgb(18, 18, 18)">REQUIRED</span></strong></p>
  <p data-lake-id="uf20565ea" id="uf20565ea"><br></p>
  <ul list="u93cfdf03">
   <li fid="u10b34663" data-lake-id="ub5089b7a" id="ub5089b7a"><strong><span data-lake-id="u96130869" id="u96130869" style="color: rgb(18, 18, 18)">REQUIRED</span></strong><span data-lake-id="u99374608" id="u99374608">，如果不存在事务则开启一个事务，如果存在事务则加入之前的事务，总是只有一个事务在执行</span></li>
   <li fid="u10b34663" data-lake-id="u81db155b" id="u81db155b"><strong><span data-lake-id="ud3b99c89" id="ud3b99c89" style="color: rgb(18, 18, 18)">REQUIRES_NEW</span></strong><span data-lake-id="u7914c086" id="u7914c086">，每次执行新开一个事务</span></li>
   <li fid="u10b34663" data-lake-id="u85be8066" id="u85be8066"><strong><span data-lake-id="uec959e5c" id="uec959e5c" style="color: rgb(18, 18, 18)">SUPPORTS</span></strong><span data-lake-id="ucc3558d6" id="ucc3558d6">，有事务则加入事务，没有事务则普通执行</span></li>
   <li fid="u10b34663" data-lake-id="uc8f44cd0" id="uc8f44cd0"><strong><span data-lake-id="uf4eb0364" id="uf4eb0364" style="color: rgb(18, 18, 18)">NOT_SUPPORTED</span></strong><span data-lake-id="u80be3ccf" id="u80be3ccf">，有事务则暂停该事务，没有则普通执行</span></li>
   <li fid="u10b34663" data-lake-id="u23cac2ba" id="u23cac2ba"><strong><span data-lake-id="ue716c447" id="ue716c447" style="color: rgb(18, 18, 18)">MANDATORY</span></strong><span data-lake-id="ud1826eaf" id="ud1826eaf">，强制有事务，没有事务则报异常</span></li>
   <li fid="u10b34663" data-lake-id="ud2ee163d" id="ud2ee163d"><strong><span data-lake-id="u1370773f" id="u1370773f" style="color: rgb(18, 18, 18)">NEVER</span></strong><span data-lake-id="ud29e52bc" id="ud29e52bc">，有事务则报异常</span></li>
   <li fid="u10b34663" data-lake-id="u6491f2d9" id="u6491f2d9"><strong><span data-lake-id="u758a5646" id="u758a5646" style="color: rgb(18, 18, 18)">NESTED</span></strong><span data-lake-id="uaec1b50e" id="uaec1b50e">，如果之前有事务，则创建嵌套事务，嵌套事务回滚不影响父事务，反之父事务影响嵌套事务</span></li>
  </ul>
  <p data-lake-id="u13c8225e" id="u13c8225e"><span data-lake-id="u36320f51" id="u36320f51">​</span><br></p>
  <h1 data-lake-id="XyXtJ" id="XyXtJ"><span data-lake-id="u9498fad9" id="u9498fad9">扩展知识</span></h1>
  <h2 data-lake-id="Fk9nW" id="Fk9nW"><span data-lake-id="u37265480" id="u37265480">用法</span></h2>
  <p data-lake-id="u094434b0" id="u094434b0"><br></p>
  <p data-lake-id="u65749937" id="u65749937"><span data-lake-id="u38f94fdc" id="u38f94fdc">假设有两个业务方法A和B，方法A在方法B中被调用，需要在事务中保证它们的一致性，如果方法A或方法B中的任何一个方法发生异常，则需要回滚事务。</span></p>
  <p data-lake-id="u95173113" id="u95173113"><span data-lake-id="udbb5551d" id="udbb5551d">​</span><br></p>
  <p data-lake-id="u39f9be7f" id="u39f9be7f"><span data-lake-id="ufd190d84" id="ufd190d84">使用Spring的事务传播机制，可以在方法A和方法B上使用相同的事务管理器，并通过设置相同的传播行为来保证事务的一致性和完整性。具体实现如下：</span></p>
  <p data-lake-id="u95d6f623" id="u95d6f623"><br></p>
  <pre lang="java"><code>
@Service
public class TransactionFooService {
    
    @Autowired
    private FooDao fooDao;
  
    
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void methodA() throws Exception {
        // do something
        fooDao.updateFoo();
    }
}

@Service
public class TransactionBarService {
    
    @Autowired
    private BarDao barDao;

  	@Autowired
  	private TransactionFooService transactionFooService;
    
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void methodB() throws Exception {
        // do something
        barDao.updateBar();
        transactionFooService.methodA();
    }
}



</code></pre>
  <p data-lake-id="ude3b6003" id="ude3b6003"><br></p>
  <p data-lake-id="u260cd4bd" id="u260cd4bd"><span data-lake-id="u02e3c807" id="u02e3c807">在上述示例中，方法A和方法B都使用了REQUIRED的传播行为，表示如果当前存在事务，则在当前事务中执行；如果当前没有事务，则创建一个新的事务。如果在方法A或方法B中出现异常，则整个事务会自动回滚。</span></p>
  <p data-lake-id="ue8ac6b06" id="ue8ac6b06"><span data-lake-id="u5f0fd416" id="u5f0fd416">​</span><br></p>
  <h2 data-lake-id="uiKwY" id="uiKwY"><span data-lake-id="u7ebe8319" id="u7ebe8319">rollbackFor</span></h2>
  <p data-lake-id="ua62771eb" id="ua62771eb"><br></p>
  <p data-lake-id="u9460990c" id="u9460990c"><span data-lake-id="u461c35ad" id="u461c35ad">rollbackFor是Spring事务中的一个属性，用于指定哪些异常会触发事务回滚。</span></p>
  <p data-lake-id="u100be021" id="u100be021"><span data-lake-id="u01fed629" id="u01fed629">​</span><br></p>
  <p data-lake-id="u642c322a" id="u642c322a"><span data-lake-id="u8c1efcca" id="u8c1efcca">在一个事务方法中，如果发生了rollbackFor属性指定的异常或其子类异常，则事务会回滚。</span><strong><span data-lake-id="u3eeefb75" id="u3eeefb75">如果不指定rollbackFor，则默认情况下只有RuntimeException和Error会触发事务回滚。</span></strong></p>
  <p data-lake-id="u1440715b" id="u1440715b"><strong><span data-lake-id="u16288489" id="u16288489">​</span></strong><br></p>
  <p data-lake-id="u1a14203a" id="u1a14203a"><strong><span data-lake-id="u008fef9c" id="u008fef9c">​</span></strong><br></p>
  <h2 data-lake-id="Fo6GX" id="Fo6GX"><span data-lake-id="ucf3b0ff9" id="ucf3b0ff9">场景题</span></h2>
  <p data-lake-id="u05246d13" id="u05246d13"><br></p>
  <p data-lake-id="uea2e0b11" id="uea2e0b11"><span data-lake-id="u3e539694" id="u3e539694">问：一个长的事务方法a，在读写分离的情况下，里面既有读库操作，也有写库操作，再调用个读库方法b，方法b该用什么传播机制呢？</span></p>
  <p data-lake-id="u01790e30" id="u01790e30"><span data-lake-id="uf918eb73" id="uf918eb73">​</span><br></p>
  <p data-lake-id="ueef5980a" id="ueef5980a"><span data-lake-id="u6e4b3bb4" id="u6e4b3bb4">这种情况，读方法如果是最后一步，直接not_supported就行了，避免读报错导致数据回滚。如果是中间步骤，最好还是要required，因为异常失败需要回滚一下。</span></p>
 </body>
</html>